package com.example.stock.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.stock.comm.Cons;
import com.example.stock.comm.FreqEnum;
import com.example.stock.comm.StrategyEnum;
import com.example.stock.entity.eo.StatParamEo;
import com.example.stock.entity.eo.StockTradeEo;
import com.example.stock.entity.mapper.StockTradeMapper;
import com.example.stock.service.IServiceBasic;
import com.example.stock.entity.service.IStatParamService;
import com.example.stock.entity.service.IStockTradeService;
import com.example.stock.vo.ModelLineMix;
import com.example.stock.vo.Series;
import com.example.stock.vo.StockTradeVo;
import com.example.stock.vo.ViewVo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/view")
public class IndexViewController {
  @Resource
  private IStockTradeService IStockTradeService;
  @Resource
  private IStatParamService IStatParamService;

  @Resource
  private StockTradeMapper stockTradeMapper;

  @Resource
  private IServiceBasic serviceBasic;

  //收益曲线
  @RequestMapping("/compare")
  public ModelLineMix getStockTrade_mix(String tsCode,String strategy,@RequestParam(required = false) List<String> tsCodes){
    List<LocalDateTime> listDate;
    List<StockTradeEo> stockTradeEos;

    if ("000000.00".equalsIgnoreCase(tsCode)) {
      //获取交易记录 - 无序
      List<StockTradeEo> tempList = stockTradeMapper.selectList(Wrappers.<StockTradeEo>lambdaQuery()
              .eq(StockTradeEo::getStrategy, StrategyEnum.getByNameExt(strategy).name())
              .in(StockTradeEo::getTsCode, tsCodes)
              .orderByAsc(StockTradeEo::getHoldTime)
      );
      if (CollectionUtil.isEmpty(tempList)) {
        return new ModelLineMix();
      }
      Map<String,StockTradeEo> firstDay = new HashMap<>();
      Map<String, List<StockTradeEo>> collect = tempList.stream().collect(Collectors.groupingBy(StockTradeEo::getTsCode));
      //排序及金额处理
      collect.forEach((k,v)-> handlerList(v));

      LocalDateTime holdTime = tempList.get(0).getHoldTime();
      collect.forEach((k,v)->{
        StockTradeEo stockTradeEo = v.get(0);
        StockTradeEo first = BeanUtil.copyProperties(stockTradeEo, StockTradeEo.class);
        first.setHoldStatus((short) 0);
        first.setHoldTime(holdTime);
        firstDay.put(k, first);
      });


      List<LocalDateTime> allTradeDay = tempList.stream().map(StockTradeEo::getHoldTime).distinct().collect(Collectors.toList());
      validAllTradeDay(allTradeDay);
      stockTradeEos = new ArrayList<>();
      for (LocalDateTime localDateTime : allTradeDay) {
        List<StockTradeEo> collect1 = tempList.stream().filter(t -> t.getHoldTime().equals(localDateTime)).collect(Collectors.toList());
        for (StockTradeEo stockTradeEo : collect1) {
          firstDay.put(stockTradeEo.getTsCode(), stockTradeEo);
        }
        Collection<StockTradeEo> values = firstDay.values();
        stockTradeEos.add(new StockTradeEo()
                .setHoldTime(localDateTime)
                .setPrice(values.stream().mapToDouble(StockTradeEo::getPrice).sum()/(values.size()))
                .setMoney(values.stream().mapToDouble(StockTradeEo::getMoney).sum()/(values.size()))
        );
      }

      /*获取时间段*/
      LocalDateTime start = tempList.get(0).getHoldTime();
      LocalDateTime end = tempList.get(tempList.size() - 1).getHoldTime();
      listDate = getList(start, end);
      
    }else {
      stockTradeEos = stockTradeMapper.selectList(Wrappers.<StockTradeEo>lambdaQuery()
              .eq(StockTradeEo::getStrategy, StrategyEnum.getByNameExt(strategy).name())
              .eq(StockTradeEo::getTsCode, tsCode)
              .orderByAsc(StockTradeEo::getHoldTime));
      if (CollectionUtil.isEmpty(stockTradeEos)) {
        return new ModelLineMix();
      }
      LocalDateTime start = stockTradeEos.get(0).getHoldTime();
      LocalDateTime end = stockTradeEos.get(stockTradeEos.size() - 1).getHoldTime();
      listDate = getList(start, end);
    }

    List<ViewVo> viewVos = IStockTradeService.getViewVo(listDate, stockTradeEos);


    List<Double> accountMoney = viewVos.stream().map(t->t.getMoney()).collect(Collectors.toList());
    List<Double> indexPrice = viewVos.stream().map(t->t.getPrice()).collect(Collectors.toList());;
    indexPrice = handler(indexPrice);

    String name = serviceBasic.getName(tsCode);
    ModelLineMix modelLineMix = new ModelLineMix();
    modelLineMix.setLengendData(Arrays.asList("指数","余额","走势","盈亏"));
    modelLineMix.setXAxisData(viewVos.stream().map(t-> t.getLocalDateTime().format(Cons.formatYyyyMM)).collect(Collectors.toList()));
    modelLineMix.setTitleName(tsCode + "\n" + name);
    Series series = new Series();
    series.setName("指数");
    series.setType("line");
    series.setData(indexPrice.stream().map(t->new BigDecimal(t/10000.0).setScale(4,RoundingMode.HALF_UP).doubleValue()).collect(Collectors.toList()));
    Series series1 = new Series();
    series1.setName("余额");
    series1.setType("line");
    series1.setData(accountMoney.stream().map(t->new BigDecimal(t/10000.0).setScale(4,RoundingMode.HALF_UP).doubleValue()).collect(Collectors.toList()));

    Series series2 = new Series();
    series2.setName("走势");
    series2.setType("bar");
    series2.setData(getRate(viewVos.stream().map(t->t.getPrice()).collect(Collectors.toList())));
    Series series3 = new Series();
    series3.setName("盈亏");
    series3.setType("bar");
    series3.setData(getRate(viewVos.stream().map(t->t.getMoney()).collect(Collectors.toList())));
    modelLineMix.setSeries(Arrays.asList(series2, series3));

    modelLineMix.setSeries(Arrays.asList(series, series1,series2,series3));
    modelLineMix.setScore(IStockTradeService.getScore(stockTradeEos));

    return modelLineMix;
  }

  private void validAllTradeDay(List<LocalDateTime> allTradeDay) {
    LocalDateTime pre = LocalDateTime.MIN;
    for (LocalDateTime localDateTime : allTradeDay) {
      if (localDateTime.isBefore(pre)) {
        throw new RuntimeException("时间有误!");
      }
      pre = localDateTime;
    }
  }

  private List<Double> getRate(List<Double> collect) {
    List<Double> doubles = new ArrayList<>();
    Double first  = collect.get(0);
    for (int i = 0; i < collect.size(); i++) {
      Double d = (collect.get(i)-first)/first*100;
      doubles.add(new BigDecimal(d).setScale(2,RoundingMode.HALF_UP).doubleValue());
      first = collect.get(i);

    }
    return doubles;
  }

  @RequestMapping("/trades")
  public List<StockTradeVo> getStockTrades(String tsCode, String strategy){
      List<StockTradeEo> stockTradeEos = stockTradeMapper.selectList(Wrappers.<StockTradeEo>lambdaQuery()
              .eq(StockTradeEo::getStrategy, StrategyEnum.getByNameExt(strategy).name())
              .eq(StockTradeEo::getTsCode, tsCode)
              .orderByDesc(StockTradeEo::getHoldTime));
      List<StockTradeVo> collect = stockTradeEos.stream().map(t -> BeanUtil.copyProperties(t, StockTradeVo.class)).collect(Collectors.toList());
      return collect;
  }

  //先排序
  private void handlerList(List<StockTradeEo> v) {
//    v.stream().sorted(Comparator.comparing(StockTradeEo::getHoldTime));
    double base = v.get(0).getPrice();
    v.forEach(eo-> eo.setPrice(eo.getPrice()/ base * 1000000.0));
  }

  private List<Double> handler(List<Double> accountMoney) {
    Double base = accountMoney.get(0);
    Function<Double, Double> doubleDoubleFunction = t -> {
      double v = t / base * 1000000.0;
      return new BigDecimal(v).setScale(3, RoundingMode.HALF_UP).doubleValue();
    };
    return accountMoney.stream().map(doubleDoubleFunction).collect(Collectors.toList());
  }

  private List<LocalDateTime> getList(LocalDateTime start, LocalDateTime end) {
    start = start.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0);
    List<LocalDateTime> localDateTimes = new ArrayList<>();
    localDateTimes.add(start);
    for (; start.isBefore(end); ) {
      start = start.plusMonths(1);
      localDateTimes.add(start);
    }
    return localDateTimes;
  }

  @RequestMapping("/param")
  public StatParamEo getStockTrades(@RequestParam("tsCodes")List<String> tsCodes, String strategy){
    List<StatParamEo> list = IStatParamService.list(Wrappers.<StatParamEo>lambdaQuery()
            .in(StatParamEo::getTsCode, tsCodes)
            .eq(StatParamEo::getStrategy, strategy)
            .eq(StatParamEo::getFreq, FreqEnum.MIN30.name())
    );
    long count = list.stream().distinct().count();
    if (count == 1) {
      return list.get(0);
    }
    return new StatParamEo();
  }
}